﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using EFDataModel;
using EFDataModel.Enums;

namespace ContactMvc4TB.Helpers.DynamicDataType
{
    /// <summary>
    /// Dient zur Erstellung von passenden Eingabefeldern für die dynamischen Eingabetypen DynamicDataTypes
    /// Zum einen zum Bearbeiten der Daten bzw. Anzeigen der Daten für die Detailsansichten
    /// </summary>
    public class DynamicDataTypeHtmlHelper
    {
        #region Member
        /// <summary>
        /// Der Aktuelle HTML Helper
        /// </summary>
        private HtmlHelper CurrentHtmlHelper { get; set; }

        /// <summary>
        /// Das Aktuelle Control als HTML-Liste sortiert nach den Kategorien, die festgelegt werden müssen für jedes Control und dem jeweils passenden Controls, welche im Value abgelegt werden
        /// </summary>
        private SortedList<DynamicDataTypeCategory, string> CurrentControl { get; set; }
        #endregion

        #region Konstruktor
        /// <summary>
        /// Konstruktor der HTML Helpers Klasse für die Kategorien. die Statische Klasse zum Instanzieieren findet man in den HtmlHelperExtensions
        /// </summary>
        public DynamicDataTypeHtmlHelper(HtmlHelper htmlHelper)
        {
            CurrentHtmlHelper = htmlHelper;
            CurrentControl = new SortedList<DynamicDataTypeCategory, string>();
        }
        #endregion

        #region Public Functions
        /// <summary>
        /// Dynamic Data Bearbeiten Felder anzeigen für das übergebene Model
        /// </summary>
        /// <param name="data">die Eingabefeld daten für den aktuellen Datensatz die angezeigt werden sollen</param>
        /// <param name="module">Das Modul für das die Felder erstellt werden sollen</param>
        public MvcHtmlString EditorFor(IEnumerable<EFDynamicData> data, EFModules module)
        {
            //Alle eingabefelder für das übergenenen Modul heraussuchen die auch angezeigt werden sollen (Hier wird dann bereits mit einer Statischen Liste gearbeitet,
            //die nur einmal geladen wird und dann als Static in der Anwendung zur Verfügung steht)
            var fields = EFDynamicDataType.GetVisibleDataTypesByModulId(module,CurrentSession.GetCurrentUser(), CurrentHttpContext.GetDataModel(), EViewType.Edit);

            //Auslesen der hinterlegten Validierungsfehler aus dem TempData, wenn bei der Eingabe Fehler aufgetreten sind, die nicht vom JavaScript abgefangen wurden dann sind diese im TempData hinterlegt.
            SortedList<int, DynamicDataValidationError> currentValidationErrors = CurrentHtmlHelper.ViewContext.TempData.ContainsKey(DynamicDataValidationError.TempDataString) ?
                                                                                  (SortedList<int, DynamicDataValidationError>)CurrentHtmlHelper.ViewContext.TempData[DynamicDataValidationError.TempDataString] :
                                                                                  new SortedList<int, DynamicDataValidationError>();

            //Alle Eingabefelder für dieses Modul durchgehen und wenn für das jeweils passende Feld Daten hinterlegt wurden diese anzeigen.
            foreach (EFDynamicDataType eDataType in fields.OrderBy(p => p.SortId))
            {
                EFDynamicData currentData = null;
                //Wenn ein neuer Datensatz erstellt wird, dann ist Data "null"
                if (data != null)
                {
                    //Heraussuchen ob für den aktuellen Datentyp Daten angezeigt werden sollen.
                    currentData = data.Where(p => p.EFDynamicDataTypeID == eDataType.ID).FirstOrDefault();
                }

                string htmlTemplate =GlobalResources.HtmlTemplates.EditorForDynamicDataTemplateRESX;
                string anzeigeLabel = CurrentHtmlHelper.Label(eDataType.Name).ToHtmlString();

                //Den aktuellen Validierungsfehler, falls einer existiert aus der Liste für den aktuellen Eingabetypen herraussuchen
                DynamicDataValidationError currentValidationError = currentValidationErrors.ContainsKey(eDataType.ID) ? currentValidationErrors[eDataType.ID] : null;

                //erstellen des passenden HTML Controls mit den passenden Validators, wenn Daten für das Eingabefeld hinterlegt wurden, diese mit übergeben.
                DynamicDataEditorControlCreator dataEditorControlCreator = new DynamicDataEditorControlCreator(CurrentHtmlHelper, eDataType, currentData != null ? currentData.GetValue() : null, currentValidationError);
                string inputControl = dataEditorControlCreator.CreateHtmlControl();

                //Prüfen ob die aktuelle Kategorie schon der Liste hinzugefügt wurde.
                if (!CurrentControl.ContainsKey(eDataType.DynamicDataTypeCategory))
                {
                    CurrentControl.Add(eDataType.DynamicDataTypeCategory, string.Empty);
                }

                //Unserer Kategorie das passende Control hinzufügen, als HTML-String
                CurrentControl[eDataType.DynamicDataTypeCategory] += string.Format(htmlTemplate, anzeigeLabel, inputControl);
            }

            //Den passenden MvcHtmlString zurück geben für unser gesamten DynamicDataControl
            return MvcHtmlString.Create(GetCompleteControl());
        }

        /// <summary>
        /// Dynamic Data Label Anzeigefelder anzeigen für das übergebene Model
        /// </summary>
        /// <param name="data">Die Daten die angezeigt werden sollen</param>
        /// <param name="module">das Modul für das die Daten angezeigt werden sollen</param>
        public MvcHtmlString DisplayFor(IEnumerable<EFDynamicData> data, EFModules module)
        {
            //Alle eingabefelder für das übergenenen Modul heraussuchen die auch angezeigt werden sollen           
            var fields = EFDynamicDataType.GetVisibleDataTypesByModulId(module, CurrentSession.GetCurrentUser(), CurrentHttpContext.GetDataModel(), EViewType.Details);

            //Alle Eingabefelder für dieses Modul durchgehen und wenn für das jeweils passende Feld Daten hinterlegt wurden diese anzeigen.
            foreach (EFDynamicDataType eDataType in fields.OrderBy(p => p.SortId))
            {
                //Heraussuchen ob für den aktuellen Datentyp Daten angezeigt werden sollen.
                EFDynamicData currentData = data.Where(p => p.EFDynamicDataTypeID == eDataType.ID).FirstOrDefault();

                string htmlTemplate =GlobalResources.HtmlTemplates.DisplayForDynamicDataTemplateRESX;
                string anzeigeLabel = CurrentHtmlHelper.Label(eDataType.Name).ToHtmlString();

                //erstellen des passenden HTML Controls mit den passenden Validators, wenn Daten für das Eingabefeld hinterlegt wurden, diese mit übergeben.
                DynamicDataDisplayControlCreator dataEditorControlCreator = new DynamicDataDisplayControlCreator(CurrentHtmlHelper, eDataType, currentData != null ? currentData.GetValue() : null);
                string displayControl = dataEditorControlCreator.CreateHtmlControl();

                //Prüfen ob die aktuelle Kategorie schon der Liste hinzugefügt wurde.
                if (!CurrentControl.ContainsKey(eDataType.DynamicDataTypeCategory))
                {
                    CurrentControl.Add(eDataType.DynamicDataTypeCategory, string.Empty);
                }

                //Unserer Kategorie das passende Control hinzufügen, als HTML-String
                CurrentControl[eDataType.DynamicDataTypeCategory] += string.Format(htmlTemplate, anzeigeLabel, displayControl);
            }

            return MvcHtmlString.Create(GetCompleteControl());
        }
        #endregion

        #region Private Functions
        /// <summary>
        /// Zusammenbauen des aktuellen Controlls. Hier werden die Kategorien mit eingebunden und das komplette Control zusammengebaut
        /// </summary>
        /// <returns>Compelttes DynamicDataTypeControl</returns>
        private string GetCompleteControl()
        {
            StringBuilder completeTemplate = new StringBuilder();
            //Alle hinterlegten Kategorien für das aktuelle Modul durchgehen und in einem Großen "Html" String zusammenbauen, damit wird die 
            //Abgrenzung der Eingabefelder zu den jeweiligen Kategorien errreicht die in jedem einzelnen Eingabefeld hinterlegt sind.
            foreach (KeyValuePair<DynamicDataTypeCategory, string> eKvp in CurrentControl.OrderBy(p=>p.Key))
            {
                completeTemplate.Append(string.Format(GlobalResources.HtmlTemplates.FieldSetTemplateRESX, eKvp.Key.Name, eKvp.Value));
            }

            return completeTemplate.ToString();
        }
        #endregion
    }
}